package com.doubao.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.doubao.common.result.Result;
import com.doubao.user.constant.UserConstant;
import com.doubao.user.entity.User;
import com.doubao.user.entity.UserDailyToken;
import com.doubao.user.mapper.UserDailyTokenMapper;
import com.doubao.user.mapper.UserMapper;
import com.doubao.user.service.UserDailyTokenService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户每日token使用记录服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserDailyTokenServiceImpl extends ServiceImpl<UserDailyTokenMapper, UserDailyToken> implements UserDailyTokenService {

    private final UserDailyTokenMapper userDailyTokenMapper;
    private final UserMapper userMapper;

    @Override
    public UserDailyToken getUserDailyToken(Long userId, LocalDate date) {
        if (userId == null || date == null) {
            return null;
        }

        LambdaQueryWrapper<UserDailyToken> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDailyToken::getUserId, userId)
                .eq(UserDailyToken::getDate, date);
        return userDailyTokenMapper.selectOne(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> createDailyToken(Long userId, LocalDate date, Integer limitTokens) {
        if (userId == null || date == null) {
            return Result.failed("参数错误");
        }

        // 检查是否已存在
        LambdaQueryWrapper<UserDailyToken> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDailyToken::getUserId, userId)
                .eq(UserDailyToken::getDate, date);
        if (userDailyTokenMapper.selectCount(wrapper) > 0) {
            return Result.success(); // 已存在，直接返回成功
        }

        // 获取用户每日限额
        Integer tokenLimit = limitTokens;
        if (tokenLimit == null) {
            User user = userMapper.selectById(userId);
            if (user != null) {
                tokenLimit = user.getTotalTokensBalance();
            } else {
                tokenLimit = UserConstant.DEFAULT_DAILY_TOKENS_LIMIT;
            }
        }

        // 创建新记录
        UserDailyToken dailyToken = new UserDailyToken();
        dailyToken.setUserId(userId);
        dailyToken.setDate(date);
        dailyToken.setPromptTokens(0);
        dailyToken.setCompletionTokens(0);
        dailyToken.setLimitTokens(tokenLimit);
        dailyToken.setCreatedAt(LocalDateTime.now());
        dailyToken.setUpdatedAt(LocalDateTime.now());

        userDailyTokenMapper.insert(dailyToken);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> increasePromptTokens(Long userId, LocalDate date, Integer tokens) {
        if (userId == null || date == null || tokens == null || tokens <= 0) {
            return Result.failed("参数错误");
        }

        String dateStr = date.toString();
        try {
            // 检查是否存在，不存在则创建
            UserDailyToken dailyToken = getUserDailyToken(userId, date);
            if (dailyToken == null) {
                createDailyToken(userId, date, null);
            }

            userDailyTokenMapper.increasePromptTokens(userId, dateStr, tokens);
            return Result.success();
        } catch (Exception e) {
            log.error("增加用户输入tokens失败", e);
            return Result.failed("增加输入tokens失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> increaseCompletionTokens(Long userId, LocalDate date, Integer tokens) {
        if (userId == null || date == null || tokens == null || tokens <= 0) {
            return Result.failed("参数错误");
        }

        String dateStr = date.toString();
        try {
            // 检查是否存在，不存在则创建
            UserDailyToken dailyToken = getUserDailyToken(userId, date);
            if (dailyToken == null) {
                createDailyToken(userId, date, null);
            }

            userDailyTokenMapper.increaseCompletionTokens(userId, dateStr, tokens);
            return Result.success();
        } catch (Exception e) {
            log.error("增加用户输出tokens失败", e);
            return Result.failed("增加输出tokens失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateTokenLimit(Long userId, LocalDate date, Integer limit) {
        if (userId == null || date == null || limit == null || limit < 0) {
            return Result.failed("参数错误");
        }

        String dateStr = date.toString();
        try {
            // 检查是否存在，不存在则创建
            UserDailyToken dailyToken = getUserDailyToken(userId, date);
            if (dailyToken == null) {
                createDailyToken(userId, date, limit);
                return Result.success();
            }

            userDailyTokenMapper.updateTokenLimit(userId, dateStr, limit);
            return Result.success();
        } catch (Exception e) {
            log.error("更新用户token限制失败", e);
            return Result.failed("更新token限制失败");
        }
    }

    @Override
    public int getUsedTokens(Long userId, LocalDate date) {
        if (userId == null || date == null) {
            return 0;
        }

        UserDailyToken dailyToken = getUserDailyToken(userId, date);
        if (dailyToken == null) {
            return 0;
        }

        return dailyToken.getPromptTokens() + dailyToken.getCompletionTokens();
    }

    @Override
    public List<UserDailyToken> getMonthlyTokens(Long userId, int year, int month) {
        if (userId == null) {
            return new ArrayList<>();
        }

        YearMonth yearMonth = YearMonth.of(year, month);
        LocalDate startDate = yearMonth.atDay(1);
        LocalDate endDate = yearMonth.atEndOfMonth();

        LambdaQueryWrapper<UserDailyToken> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserDailyToken::getUserId, userId)
                .ge(UserDailyToken::getDate, startDate)
                .le(UserDailyToken::getDate, endDate)
                .orderByAsc(UserDailyToken::getDate);

        return userDailyTokenMapper.selectList(wrapper);
    }

    @Override
    public List<Map<String, Object>> getMonthlyTrend(Long userId, int year, int month) {
        List<UserDailyToken> monthlyTokens = getMonthlyTokens(userId, year, month);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
        List<Map<String, Object>> trendData = new ArrayList<>();

        for (UserDailyToken token : monthlyTokens) {
            Map<String, Object> dayData = new HashMap<>();
            dayData.put("date", token.getDate().format(formatter));
            dayData.put("promptTokens", token.getPromptTokens());
            dayData.put("completionTokens", token.getCompletionTokens());
            dayData.put("total", token.getPromptTokens() + token.getCompletionTokens());
            dayData.put("limit", token.getLimitTokens());
            trendData.add(dayData);
        }

        return trendData;
    }

    @Override
    public boolean isTokenLimitExceeded(Long userId) {
        if (userId == null) {
            return true;
        }

        // 获取用户信息，查询限额
        User user = userMapper.selectById(userId);
        if (user == null) {
            return true;
        }

        LocalDate today = LocalDate.now();
        int usedTokens = getUsedTokens(userId, today);
        return usedTokens >= user.getTotalTokensBalance();
    }

    @Override
    public int getAvailableTokens(Long userId) {
        if (userId == null) {
            return 0;
        }

        // 获取用户信息，查询限额
        User user = userMapper.selectById(userId);
        if (user == null) {
            return 0;
        }

        LocalDate today = LocalDate.now();
        int usedTokens = getUsedTokens(userId, today);
        int available = user.getTotalTokensBalance() - usedTokens;
        return Math.max(0, available);
    }
}